/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.piwicode.bywordofmouth;

import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author pierre
 */
public class Hasher {

    private final static Logger LOG = Logger.getLogger(Hasher.class.getName());
    private static final String ALGO = "SHA-1";
    private static final int BUFFER_SIZE = 1024 * 64;
    private static final int CHUNK_SIZE = 1024 * 512;
    final MessageDigest md;
    final byte buffer[] = new byte[BUFFER_SIZE];

    public Hasher() throws NoSuchAlgorithmException {
        md = MessageDigest.getInstance(ALGO);
    }

    public ImmutableList<Hash> hash(File file) throws IOException, InterruptedException {
        LOG.log(Level.FINEST, "Hashing {0}", file);
        final ImmutableList.Builder<Hash> hashBldr = ImmutableList.builder();
        try (FileInputStream fis = new FileInputStream(file)) {
            int count = 0;
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    throw new InterruptedException();
                }
                //Read till the end of the chunk or till the end of the buffer
                int readed = fis.read(buffer, 0, Math.min(CHUNK_SIZE - count, buffer.length));
                if (readed == -1) {
                    hashBldr.add(new Hash(md.digest()));
                    break;
                }
                md.update(buffer, 0, readed);
                count+=readed;
                if (count == CHUNK_SIZE) {
                    hashBldr.add(new Hash(md.digest()));
                    count = 0;
                    md.reset();
                }
            }
        }
        final ImmutableList<Hash> result = hashBldr.build();
        LOG.log(Level.FINEST, "Done with {0} hash", result.size());
        return result;
    }
}
